Synopsis

Evaluation of the third round of scoring Miguel Vázquez did for the DSP.

Libraries

require(data.table)
require(ggplot2)
require(xlsx)
require(gridExtra)
require(splitstackshape)

Upload data

dsp_scored_rd1 <- unique(fread("../round1/DarkSpace-v1.txt",sep="\t",header=T,skip=1))
dsp_scored_rd2 <- unique(data.table(read.xlsx2("../round2/DarkSpace_rank2.xls",sheetIndex=1,header=T,colClasses = c("character","numeric","character","integer","character","numeric","numeric"))))
dsp_scored_rd3 <- unique(fread("./pmid_ranks.txt",header=T))

Preformat latest evaluation

colnames(dsp_scored_rd3) <- tolower(gsub("-| ","_",colnames(dsp_scored_rd3)))
colnames(dsp_scored_rd3) <- tolower(gsub("#|\\(|\\)","",colnames(dsp_scored_rd3)))
dsp_scored_rd3 <- dsp_scored_rd3[,known:=ifelse(known_pairs=="",
                                                "false",
                                                "true")]
table(dsp_scored_rd3$known,useNA = "ifany")

false  true 
80446 33869 

Explore data

I check the distribution of the relevance and the combined score separating IMEx positive and negative publications and comparing the previous iterations with the current one.

Relevance score plot

g1 <- ggplot(dsp_scored_rd1,aes(x=Relevance,fill=IMEX))
g1 <- g1 + geom_histogram(alpha=0.8,position='identity')
g1 <- g1 + xlab("relevance score")
g1 <- g1 + ylab("Number of publications")
g1 <- g1 + ggtitle("Relevance score distribution, round 1")
#g1 <- g1 + xlim(0.0,2.0)
g1 <- g1 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g2 <- ggplot(dsp_scored_rd2,aes(x=Relevance,fill=IMEX))
g2 <- g2 + geom_histogram(alpha=0.8,position='identity')
g2 <- g2 + xlab("relevance score")
g2 <- g2 + ylab("Number of publications")
g2 <- g2 + ggtitle("Relevance score distribution, round 2")
#g2 <- g2 + xlim(0.0,2.0)
g2 <- g2 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3 <- ggplot(dsp_scored_rd3,aes(x=relevance,fill=known))
g3 <- g3 + geom_histogram(alpha=0.8,position='identity')
g3 <- g3 + xlab("relevance score")
g3 <- g3 + ylab("Number of publications")
g3 <- g3 + ggtitle("Relevance score distribution, round 3")
g3 <- g3 + scale_x_continuous(breaks=c(0:24))
g3 <- g3 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
grid.arrange(g1, g2, g3, ncol=1)

g1.1 <- ggplot(dsp_scored_rd1,aes(x=Relevance,fill=IMEX))
g1.1 <- g1.1 + geom_density(alpha=0.8,position='identity')
g1.1 <- g1.1 + xlab("relevance score")
g1.1 <- g1.1 + ylab("Number of publications")
g1.1 <- g1.1 + ggtitle("Relevance score distribution, round 1")
#g1.1 <- g1.1 + xlim(0.0,2.0)
g1.1 <- g1.1 + ylim(0,5)
g1.1 <- g1.1 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g2.1 <- ggplot(dsp_scored_rd2,aes(x=Relevance,fill=IMEX))
g2.1 <- g2.1 + geom_density(alpha=0.8,position='identity')
g2.1 <- g2.1 + xlab("relevance score")
g2.1 <- g2.1 + ylab("Number of publications")
g2.1 <- g2.1 + ggtitle("Relevance score distribution, round 2")
#g2.1 <- g2.1 + xlim(0.0,2.0)
g2.1 <- g2.1 + ylim(0,5)
g2.1 <- g2.1 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.1 <- ggplot(dsp_scored_rd3,aes(x=relevance,fill=known))
g3.1 <- g3.1 + geom_density(alpha=0.8,position='identity')
g3.1 <- g3.1 + xlab("relevance score")
g3.1 <- g3.1 + ylab("Number of publications")
g3.1 <- g3.1 + ggtitle("Relevance score distribution, round 3")
g3.1 <- g3.1 + scale_x_continuous(breaks=c(0:24))
g3.1 <- g3.1 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
grid.arrange(g1.1, g2.1, g3.1, ncol=1)

The re-calculated score is certainly distributed differently from previous instances. It is also a more complex approach, so I need to explore other angles.

g3.2 <- ggplot(dsp_scored_rd3,aes(x=relevance,y=dark_space_interest,colour=known))
g3.2 <- g3.2 + geom_point(alpha=0.5)
g3.2 <- g3.2 + xlab("relevance score")
g3.2 <- g3.2 + ylab("dsp interest (truncated top at 100)")
g3.2 <- g3.2 + ggtitle("Relevance score vs Dark Space interest")
g3.2 <- g3.2 + ylim(0.0,100)
g3.2 <- g3.2 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.3 <- ggplot(dsp_scored_rd3,aes(x=relevance,y=dark_space_interest,colour=known))
g3.3 <- g3.3 + geom_smooth(alpha=0.5)
g3.3 <- g3.3 + xlab("relevance score")
g3.3 <- g3.3 + ylab("dsp interest")
g3.3 <- g3.3 + ggtitle("Relevance score vs Dark Space interest, smooth plot")
#g3.3 <- g3.3 + ylim(0.0,7)
g3.3 <- g3.3 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.4 <- ggplot(dsp_scored_rd3,aes(x=relevance,y=dark_space_interest,colour=known))
g3.4 <- g3.4 + geom_smooth(method="lm",formula=y~x,alpha=0.5)
g3.4 <- g3.4 + xlab("relevance score")
g3.4 <- g3.4 + ylab("dsp interest")
g3.4 <- g3.4 + ggtitle("Relevance score vs Dark Space interest, LM fitted")
#g3.4 <- g3.4 + ylim(0.0,7)
g3.4 <- g3.4 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
grid.arrange(g3.2, g3.3, g3.4, ncol=1)

g3.5 <- ggplot(dsp_scored_rd3,aes(x=relevance,y=dark_space_partial_interest,colour=known))
Warning message:
In scan(file = file, what = what, sep = sep, quote = quote, dec = dec,  :
  EOF within quoted string
g3.5 <- g3.5 + geom_point(alpha=0.5)
g3.5 <- g3.5 + xlab("relevance score")
g3.5 <- g3.5 + ylab("dsp partial interest (truncated top at 100)")
g3.5 <- g3.5 + ggtitle("Relevance score vs Dark Space interest")
g3.5 <- g3.5 + ylim(0.0,100)
g3.5 <- g3.5 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.6 <- ggplot(dsp_scored_rd3,aes(x=relevance,y=dark_space_partial_interest,colour=known))
g3.6 <- g3.6 + geom_smooth(alpha=0.5)
g3.6 <- g3.6 + xlab("relevance score")
g3.6 <- g3.6 + ylab("dsp partial interest")
g3.6 <- g3.6 + ggtitle("Relevance score vs Dark Space interest, smooth plot")
#g3.6 <- g3.6 + ylim(0.0,7)
g3.6 <- g3.6 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.7 <- ggplot(dsp_scored_rd3,aes(x=relevance,y=dark_space_partial_interest,colour=known))
g3.7 <- g3.7 + geom_smooth(method="lm",formula=y~x,alpha=0.5)
g3.7 <- g3.7 + xlab("relevance score")
g3.7 <- g3.7 + ylab("dsp partial interest")
g3.7 <- g3.7 + ggtitle("Relevance score vs Dark Space interest, LM fitted")
#g3.7 <- g3.7 + ylim(0.0,7)
g3.7 <- g3.7 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
grid.arrange(g3.5, g3.6, g3.7, ncol=1)

It seems the interest scores plot against the relevance score as expected, having highly interesting proteins in the ‘darkest’ areas of the dataset.

Checking distribution of scores by data source

Obtain DSP comparison table for reference

I will take the table that does the comparison at the publication level only for this comparison.

if(!exists("dsp_pubcomp")){
        setwd("~/Documents/Projects/dsp/darkspaceproject/dsp_comparison/results/")
        dsp_pubcompNames = fread('cat pubcomp_table_final.txt.gz | gunzip | head -n 1')[, colnames(.SD)]
        dsp_pubcomp = fread('cat pubcomp_table_final.txt.gz | gunzip | grep -v "^Day"')
        setnames(dsp_pubcomp, dsp_pubcompNames)
        setwd("~/Documents/Projects/dsp/DarkSpace/manual_evaluation/round2/")
}
The working directory was changed to /Users/ppm/Documents/Projects/dsp/DarkSpace/manual_evaluation/round2 inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the the working directory for notebook chunks.
Incorporating & formatting dataset info to ranked lists
dsp_scored_rd3_ori_long <- reshape(dsp_scored_rd3_ori_sel,direction="long",v.names="origin",varying=c("imex","reactome","tm_epmc","EVEX","BioGRID","GO_IPI","OmniPath_interactions","OmniPath_ptm"))
dsp_scored_rd3_ori_long_sel <- unique(dsp_scored_rd3_ori_long[order(pmid,-origin),.(pmid,relevance,known,db_score,dark_space_interest,dark_space_partial_interest,origin,id)])
dsp_scored_rd3_ori_long_sel$select <- "yes"
for (i in 2:nrow(dsp_scored_rd3_ori_long_sel)){
        if(dsp_scored_rd3_ori_long_sel[i,]$pmid == dsp_scored_rd3_ori_long_sel[i-1,]$pmid & dsp_scored_rd3_ori_long_sel[i,]$origin=="0"){
                dsp_scored_rd3_ori_long_sel[i,]$select <- "no"
        }
        
}
dsp_scored_rd3_ori_long_final <- dsp_scored_rd3_ori_long_sel[select=="yes",.(pmid,relevance,known,db_score,dark_space_interest,dark_space_partial_interest,origin,id)]
table(dsp_scored_rd3_ori_long_final$known,dsp_scored_rd3_ori_long_final$origin,useNA = "ifany")
       
        BioGRID  EVEX GO_IPI  IMEx OmniPath_interactions OmniPath_ptm reactome tm_epmc
  false     741 44947    191   385                  5145         1750     1941   30448
  true    23498  9333   4841  8594                  1450          856     1102    3596

The

Plots origin comparison
g3.8 <- ggplot(dsp_scored_rd3_ori_long_final,aes(x=relevance,fill=known))
g3.8 <- g3.8 + geom_histogram(alpha=0.8,position='identity')
g3.8 <- g3.8 + xlab("relevance score")
g3.8 <- g3.8 + ylab("Number of publications")
g3.8 <- g3.8 + ggtitle("Relevance score distribution, round 3")
g3.8 <- g3.8 + facet_grid(origin~.,scales="free_y")
g3.8 <- g3.8 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.8

g3.9 <- ggplot(dsp_scored_rd3_ori_long_final,aes(x=relevance,fill=known))
g3.9 <- g3.9 + geom_density(alpha=0.9,position='identity')
g3.9 <- g3.9 + xlab("relevance score")
g3.9 <- g3.9 + ylab("Number of publications")
g3.9 <- g3.9 + ggtitle("Relevance score distribution, round 3")
g3.9 <- g3.9 + facet_grid(origin~.,scales="free_y")
g3.9 <- g3.9 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.9

Checking dsp interest vs relevance score

g3.10 <- ggplot(dsp_scored_rd3_ori_long_final,aes(x=relevance,y=dark_space_interest,colour=known))
g3.10 <- g3.10 + geom_point(alpha=0.5)
g3.10 <- g3.10 + xlab("relevance score")
g3.10 <- g3.10 + ylab("dsp interest (truncated top at 100)")
g3.10 <- g3.10 + ggtitle("Relevance score vs Dark Space interest, per origin")
g3.10 <- g3.10 + facet_grid(origin~.,scales="free_y")
g3.10 <- g3.10 + ylim(0.0,100)
g3.10 <- g3.10 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.10

g3.11 <- ggplot(dsp_scored_rd3_ori_long_final,aes(x=relevance,y=dark_space_interest,colour=known))
g3.11 <- g3.11 + geom_smooth(alpha=0.5)
g3.11 <- g3.11 + xlab("relevance score")
g3.11 <- g3.11 + ylab("dsp interest")
g3.11 <- g3.11 + ggtitle("Relevance score vs Dark Space interest, smooth plot")
g3.11 <- g3.11 + facet_grid(origin~.,scales="free_y")
g3.11 <- g3.11 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.11

g3.12 <- ggplot(dsp_scored_rd3_ori_long_final,aes(x=relevance,y=dark_space_interest,colour=known))
g3.12 <- g3.12 + geom_smooth(method="lm",formula=y~x,alpha=0.5)
g3.12 <- g3.12 + xlab("relevance score")
g3.12 <- g3.12 + ylab("dsp interest")
g3.12 <- g3.12 + ggtitle("Relevance score vs Dark Space interest, LM fitted")
g3.12 <- g3.12 + facet_grid(origin~.,scales="free_y")
g3.12 <- g3.12 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g3.12

Comparison with round 1

After manual evaluation, it seems the relevance score has lost the power to predict whether a publication contains interactions or not. I will compare to the first round of scoring to see where lie the differences.

Merge datasets

dsp_scored_rd1$pmid <- as.character(dsp_scored_rd1$`#ID`)
dsp_scored_rd1_sel <- dsp_scored_rd1[,.(pmid,
                                        rel_rd1=Relevance,
                                        IMEX,
                                        Coverage,
                                        Proteins,
                                        prot_interest = `Protein interest`,
                                        comb_score = `Combined score`)]
        
dsp_scored_rd1_plus_3 <- data.table(unique(merge(dsp_scored_rd1_sel,dsp_scored_rd3_ori_sel,by="pmid",all = T)))
table(dsp_scored_rd1_plus_3$known,dsp_scored_rd1_plus_3$IMEX,useNA = "ifany")
       
        false  true
  false 80061   385
  true  25275  8594

There are 385 IMEx entries that are not in the ‘known’ set. How is that possible? Most importantly, over 25,000 known publications are not part of the IMEx dataset. This will be mostly BioGRID data.

Plot relevance rd1 vs rd3

First I will explore how the different relevance scores relate to each other.

g4 <- ggplot(dsp_scored_rd1_plus_3,aes(x=relevance,y=rel_rd1,colour=known,group=IMEX))
#g4 <- g4 + geom_point(alpha=0.5,aes(shape=IMEX))
g4 <- g4 + geom_point(alpha=0.5)
g4 <- g4 + xlab("relevance score rd3")
g4 <- g4 + ylab("relevance score rd1")
g4 <- g4 + ggtitle("Relevance score rd1 vs rd3")
g4 <- g4 + facet_grid(IMEX~.,scales="free_y")
#g4 <- g4 + ylim(0.0,100)
g4 <- g4 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g4

Now I represent the same plot by source data. I need to wrangle the comparison to ‘long’ format first.

table(dsp_scored_rd1_plus_3_long_final$known,dsp_scored_rd1_plus_3_long_final$origin,useNA="ifany")
       
        BioGRID  EVEX GO_IPI  IMEx OmniPath_interactions OmniPath_ptm reactome tm_epmc
  false     741 44947    191   385                  5145         1750     1941   30448
  true    23498  9333   4841  8594                  1450          856     1102    3596
g5 <- ggplot(dsp_scored_rd1_plus_3_long_final,aes(x=relevance,y=rel_rd1,colour=origin,group=known))
#g5 <- g5 + geom_point(alpha=0.5,aes(shape=IMEX))
g5 <- g5 + geom_point(alpha=0.2)
g5 <- g5 + xlab("relevance score rd3")
g5 <- g5 + ylab("relevance score rd1")
g5 <- g5 + ggtitle("Relevance score rd1 vs rd3")
g5 <- g5 + facet_grid(known~.)
#g5 <- g5 + ylim(0.0,100)
g5 <- g5 + theme(plot.title = element_text(),
               panel.grid.major = element_blank(),
               panel.grid.minor = element_blank(),
               panel.background = element_blank())
g5

LS0tCnRpdGxlOiAiUXVpY2sgZXZhbHVhdGlvbiBNaWd1ZWwgc2NvcmVzLCByb3VuZCAzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgojIyMgU3lub3BzaXMKCkV2YWx1YXRpb24gb2YgdGhlIHRoaXJkIHJvdW5kIG9mIHNjb3JpbmcgTWlndWVsIFbDoXpxdWV6IGRpZCBmb3IgdGhlIERTUC4KCiMjIyMgTGlicmFyaWVzCmBgYHtyIGxpYnJhcmllcyxtZXNzYWdlPUZBTFNFLHdhcm5pbmc9RkFMU0V9CmR5bi5sb2FkKCcvTGlicmFyeS9KYXZhL0phdmFWaXJ0dWFsTWFjaGluZXMvamRrMS44LjBfMTMxLmpkay9Db250ZW50cy9Ib21lL2pyZS9saWIvc2VydmVyL2xpYmp2bS5keWxpYicpCmxpYnJhcnkockphdmEpCnJlcXVpcmUoZGF0YS50YWJsZSkKcmVxdWlyZShnZ3Bsb3QyKQpyZXF1aXJlKHhsc3gpCnJlcXVpcmUoZ3JpZEV4dHJhKQpyZXF1aXJlKHNwbGl0c3RhY2tzaGFwZSkKYGBgCgojIyMgVXBsb2FkIGRhdGEKYGBge3IgdXBsb2FkLHdhcm5pbmc9RkFMU0UsbWVzc2FnZT1GQUxTRX0KZHNwX3Njb3JlZF9yZDEgPC0gdW5pcXVlKGZyZWFkKCIuLi9yb3VuZDEvRGFya1NwYWNlLXYxLnR4dCIsc2VwPSJcdCIsaGVhZGVyPVQsc2tpcD0xKSkKZHNwX3Njb3JlZF9yZDIgPC0gdW5pcXVlKGRhdGEudGFibGUocmVhZC54bHN4MigiLi4vcm91bmQyL0RhcmtTcGFjZV9yYW5rMi54bHMiLHNoZWV0SW5kZXg9MSxoZWFkZXI9VCxjb2xDbGFzc2VzID0gYygiY2hhcmFjdGVyIiwibnVtZXJpYyIsImNoYXJhY3RlciIsImludGVnZXIiLCJjaGFyYWN0ZXIiLCJudW1lcmljIiwibnVtZXJpYyIpKSkpCmRzcF9zY29yZWRfcmQzIDwtIHVuaXF1ZShmcmVhZCgiLi9wbWlkX3JhbmtzLnR4dCIsaGVhZGVyPVQpKQpgYGAKCiMjIyBQcmVmb3JtYXQgbGF0ZXN0IGV2YWx1YXRpb24KYGBge3IgcHJlZm9ybWF0X2RhdGEsd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpjb2xuYW1lcyhkc3Bfc2NvcmVkX3JkMykgPC0gdG9sb3dlcihnc3ViKCItfCAiLCJfIixjb2xuYW1lcyhkc3Bfc2NvcmVkX3JkMykpKQpjb2xuYW1lcyhkc3Bfc2NvcmVkX3JkMykgPC0gdG9sb3dlcihnc3ViKCIjfFxcKHxcXCkiLCIiLGNvbG5hbWVzKGRzcF9zY29yZWRfcmQzKSkpCgpkc3Bfc2NvcmVkX3JkMyA8LSBkc3Bfc2NvcmVkX3JkM1ssa25vd246PWlmZWxzZShrbm93bl9wYWlycz09IiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJmYWxzZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJ0cnVlIildCnRhYmxlKGRzcF9zY29yZWRfcmQzJGtub3duLHVzZU5BID0gImlmYW55IikKYGBgCgojIyMgRXhwbG9yZSBkYXRhCgpJIGNoZWNrIHRoZSBkaXN0cmlidXRpb24gb2YgdGhlIHJlbGV2YW5jZSBhbmQgdGhlIGNvbWJpbmVkIHNjb3JlIHNlcGFyYXRpbmcgSU1FeCBwb3NpdGl2ZSBhbmQgbmVnYXRpdmUgcHVibGljYXRpb25zIGFuZCBjb21wYXJpbmcgdGhlIHByZXZpb3VzIGl0ZXJhdGlvbnMgd2l0aCB0aGUgY3VycmVudCBvbmUuCgojIyMjIFJlbGV2YW5jZSBzY29yZSBwbG90CmBgYHtyIHJlbF9wbG90fQpnMSA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDEsYWVzKHg9UmVsZXZhbmNlLGZpbGw9SU1FWCkpCmcxIDwtIGcxICsgZ2VvbV9oaXN0b2dyYW0oYWxwaGE9MC44LHBvc2l0aW9uPSdpZGVudGl0eScpCmcxIDwtIGcxICsgeGxhYigicmVsZXZhbmNlIHNjb3JlIikKZzEgPC0gZzEgKyB5bGFiKCJOdW1iZXIgb2YgcHVibGljYXRpb25zIikKZzEgPC0gZzEgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgZGlzdHJpYnV0aW9uLCByb3VuZCAxIikKI2cxIDwtIGcxICsgeGxpbSgwLjAsMi4wKQpnMSA8LSBnMSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmcyIDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkMixhZXMoeD1SZWxldmFuY2UsZmlsbD1JTUVYKSkKZzIgPC0gZzIgKyBnZW9tX2hpc3RvZ3JhbShhbHBoYT0wLjgscG9zaXRpb249J2lkZW50aXR5JykKZzIgPC0gZzIgKyB4bGFiKCJyZWxldmFuY2Ugc2NvcmUiKQpnMiA8LSBnMiArIHlsYWIoIk51bWJlciBvZiBwdWJsaWNhdGlvbnMiKQpnMiA8LSBnMiArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSBkaXN0cmlidXRpb24sIHJvdW5kIDIiKQojZzIgPC0gZzIgKyB4bGltKDAuMCwyLjApCmcyIDwtIGcyICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKZzMgPC0gZ2dwbG90KGRzcF9zY29yZWRfcmQzLGFlcyh4PXJlbGV2YW5jZSxmaWxsPWtub3duKSkKZzMgPC0gZzMgKyBnZW9tX2hpc3RvZ3JhbShhbHBoYT0wLjgscG9zaXRpb249J2lkZW50aXR5JykKZzMgPC0gZzMgKyB4bGFiKCJyZWxldmFuY2Ugc2NvcmUiKQpnMyA8LSBnMyArIHlsYWIoIk51bWJlciBvZiBwdWJsaWNhdGlvbnMiKQpnMyA8LSBnMyArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSBkaXN0cmlidXRpb24sIHJvdW5kIDMiKQpnMyA8LSBnMyArIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygwOjI0KSkKZzMgPC0gZzMgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCgpncmlkLmFycmFuZ2UoZzEsIGcyLCBnMywgbmNvbD0xKQpgYGAKCmBgYHtyIHJlbF9wbG90X3YyfQpnMS4xIDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkMSxhZXMoeD1SZWxldmFuY2UsZmlsbD1JTUVYKSkKZzEuMSA8LSBnMS4xICsgZ2VvbV9kZW5zaXR5KGFscGhhPTAuOCxwb3NpdGlvbj0naWRlbnRpdHknKQpnMS4xIDwtIGcxLjEgKyB4bGFiKCJyZWxldmFuY2Ugc2NvcmUiKQpnMS4xIDwtIGcxLjEgKyB5bGFiKCJOdW1iZXIgb2YgcHVibGljYXRpb25zIikKZzEuMSA8LSBnMS4xICsgZ2d0aXRsZSgiUmVsZXZhbmNlIHNjb3JlIGRpc3RyaWJ1dGlvbiwgcm91bmQgMSIpCiNnMS4xIDwtIGcxLjEgKyB4bGltKDAuMCwyLjApCmcxLjEgPC0gZzEuMSArIHlsaW0oMCw1KQpnMS4xIDwtIGcxLjEgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCgpnMi4xIDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkMixhZXMoeD1SZWxldmFuY2UsZmlsbD1JTUVYKSkKZzIuMSA8LSBnMi4xICsgZ2VvbV9kZW5zaXR5KGFscGhhPTAuOCxwb3NpdGlvbj0naWRlbnRpdHknKQpnMi4xIDwtIGcyLjEgKyB4bGFiKCJyZWxldmFuY2Ugc2NvcmUiKQpnMi4xIDwtIGcyLjEgKyB5bGFiKCJOdW1iZXIgb2YgcHVibGljYXRpb25zIikKZzIuMSA8LSBnMi4xICsgZ2d0aXRsZSgiUmVsZXZhbmNlIHNjb3JlIGRpc3RyaWJ1dGlvbiwgcm91bmQgMiIpCiNnMi4xIDwtIGcyLjEgKyB4bGltKDAuMCwyLjApCmcyLjEgPC0gZzIuMSArIHlsaW0oMCw1KQpnMi4xIDwtIGcyLjEgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCgpnMy4xIDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkMyxhZXMoeD1yZWxldmFuY2UsZmlsbD1rbm93bikpCmczLjEgPC0gZzMuMSArIGdlb21fZGVuc2l0eShhbHBoYT0wLjgscG9zaXRpb249J2lkZW50aXR5JykKZzMuMSA8LSBnMy4xICsgeGxhYigicmVsZXZhbmNlIHNjb3JlIikKZzMuMSA8LSBnMy4xICsgeWxhYigiTnVtYmVyIG9mIHB1YmxpY2F0aW9ucyIpCmczLjEgPC0gZzMuMSArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSBkaXN0cmlidXRpb24sIHJvdW5kIDMiKQpnMy4xIDwtIGczLjEgKyBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMDoyNCkpCmczLjEgPC0gZzMuMSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmdyaWQuYXJyYW5nZShnMS4xLCBnMi4xLCBnMy4xLCBuY29sPTEpCmBgYAoKVGhlIHJlLWNhbGN1bGF0ZWQgc2NvcmUgaXMgY2VydGFpbmx5IGRpc3RyaWJ1dGVkIGRpZmZlcmVudGx5IGZyb20gcHJldmlvdXMgaW5zdGFuY2VzLiBJdCBpcyBhbHNvIGEgbW9yZSBjb21wbGV4IGFwcHJvYWNoLCBzbyBJIG5lZWQgdG8gZXhwbG9yZSBvdGhlciBhbmdsZXMuIAoKYGBge3IgZXhwbG9yYXRvcnl9CmczLjIgPC0gZ2dwbG90KGRzcF9zY29yZWRfcmQzLGFlcyh4PXJlbGV2YW5jZSx5PWRhcmtfc3BhY2VfaW50ZXJlc3QsY29sb3VyPWtub3duKSkKZzMuMiA8LSBnMy4yICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpCmczLjIgPC0gZzMuMiArIHhsYWIoInJlbGV2YW5jZSBzY29yZSIpCmczLjIgPC0gZzMuMiArIHlsYWIoImRzcCBpbnRlcmVzdCAodHJ1bmNhdGVkIHRvcCBhdCAxMDApIikKZzMuMiA8LSBnMy4yICsgZ2d0aXRsZSgiUmVsZXZhbmNlIHNjb3JlIHZzIERhcmsgU3BhY2UgaW50ZXJlc3QiKQpnMy4yIDwtIGczLjIgKyB5bGltKDAuMCwxMDApCmczLjIgPC0gZzMuMiArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmczLjMgPC0gZ2dwbG90KGRzcF9zY29yZWRfcmQzLGFlcyh4PXJlbGV2YW5jZSx5PWRhcmtfc3BhY2VfaW50ZXJlc3QsY29sb3VyPWtub3duKSkKZzMuMyA8LSBnMy4zICsgZ2VvbV9zbW9vdGgoYWxwaGE9MC41KQpnMy4zIDwtIGczLjMgKyB4bGFiKCJyZWxldmFuY2Ugc2NvcmUiKQpnMy4zIDwtIGczLjMgKyB5bGFiKCJkc3AgaW50ZXJlc3QiKQpnMy4zIDwtIGczLjMgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCwgc21vb3RoIHBsb3QiKQojZzMuMyA8LSBnMy4zICsgeWxpbSgwLjAsNykKZzMuMyA8LSBnMy4zICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKZzMuNCA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDMsYWVzKHg9cmVsZXZhbmNlLHk9ZGFya19zcGFjZV9pbnRlcmVzdCxjb2xvdXI9a25vd24pKQpnMy40IDwtIGczLjQgKyBnZW9tX3Ntb290aChtZXRob2Q9ImxtIixmb3JtdWxhPXl+eCxhbHBoYT0wLjUpCmczLjQgPC0gZzMuNCArIHhsYWIoInJlbGV2YW5jZSBzY29yZSIpCmczLjQgPC0gZzMuNCArIHlsYWIoImRzcCBpbnRlcmVzdCIpCmczLjQgPC0gZzMuNCArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSB2cyBEYXJrIFNwYWNlIGludGVyZXN0LCBMTSBmaXR0ZWQiKQojZzMuNCA8LSBnMy40ICsgeWxpbSgwLjAsNykKZzMuNCA8LSBnMy40ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKZ3JpZC5hcnJhbmdlKGczLjIsIGczLjMsIGczLjQsIG5jb2w9MSkKYGBgCgpgYGB7ciBleHBsb3JhdG9yeV8yfQpnMy41IDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkMyxhZXMoeD1yZWxldmFuY2UseT1kYXJrX3NwYWNlX3BhcnRpYWxfaW50ZXJlc3QsY29sb3VyPWtub3duKSkKZzMuNSA8LSBnMy41ICsgZ2VvbV9wb2ludChhbHBoYT0wLjUpCmczLjUgPC0gZzMuNSArIHhsYWIoInJlbGV2YW5jZSBzY29yZSIpCmczLjUgPC0gZzMuNSArIHlsYWIoImRzcCBwYXJ0aWFsIGludGVyZXN0ICh0cnVuY2F0ZWQgdG9wIGF0IDEwMCkiKQpnMy41IDwtIGczLjUgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCIpCmczLjUgPC0gZzMuNSArIHlsaW0oMC4wLDEwMCkKZzMuNSA8LSBnMy41ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKZzMuNiA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDMsYWVzKHg9cmVsZXZhbmNlLHk9ZGFya19zcGFjZV9wYXJ0aWFsX2ludGVyZXN0LGNvbG91cj1rbm93bikpCmczLjYgPC0gZzMuNiArIGdlb21fc21vb3RoKGFscGhhPTAuNSkKZzMuNiA8LSBnMy42ICsgeGxhYigicmVsZXZhbmNlIHNjb3JlIikKZzMuNiA8LSBnMy42ICsgeWxhYigiZHNwIHBhcnRpYWwgaW50ZXJlc3QiKQpnMy42IDwtIGczLjYgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCwgc21vb3RoIHBsb3QiKQojZzMuNiA8LSBnMy42ICsgeWxpbSgwLjAsNykKZzMuNiA8LSBnMy42ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKZzMuNyA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDMsYWVzKHg9cmVsZXZhbmNlLHk9ZGFya19zcGFjZV9wYXJ0aWFsX2ludGVyZXN0LGNvbG91cj1rbm93bikpCmczLjcgPC0gZzMuNyArIGdlb21fc21vb3RoKG1ldGhvZD0ibG0iLGZvcm11bGE9eX54LGFscGhhPTAuNSkKZzMuNyA8LSBnMy43ICsgeGxhYigicmVsZXZhbmNlIHNjb3JlIikKZzMuNyA8LSBnMy43ICsgeWxhYigiZHNwIHBhcnRpYWwgaW50ZXJlc3QiKQpnMy43IDwtIGczLjcgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCwgTE0gZml0dGVkIikKI2czLjcgPC0gZzMuNyArIHlsaW0oMC4wLDcpCmczLjcgPC0gZzMuNyArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmdyaWQuYXJyYW5nZShnMy41LCBnMy42LCBnMy43LCBuY29sPTEpCmBgYApJdCBzZWVtcyB0aGUgaW50ZXJlc3Qgc2NvcmVzIHBsb3QgYWdhaW5zdCB0aGUgcmVsZXZhbmNlIHNjb3JlIGFzIGV4cGVjdGVkLCBoYXZpbmcgaGlnaGx5IGludGVyZXN0aW5nIHByb3RlaW5zIGluIHRoZSAnZGFya2VzdCcgYXJlYXMgb2YgdGhlIGRhdGFzZXQuIAoKIyMjIENoZWNraW5nIGRpc3RyaWJ1dGlvbiBvZiBzY29yZXMgYnkgZGF0YSBzb3VyY2UKCiMjIyMjIE9idGFpbiBEU1AgY29tcGFyaXNvbiB0YWJsZSBmb3IgcmVmZXJlbmNlCkkgd2lsbCB0YWtlIHRoZSB0YWJsZSB0aGF0IGRvZXMgdGhlIGNvbXBhcmlzb24gYXQgdGhlIHB1YmxpY2F0aW9uIGxldmVsIG9ubHkgZm9yIHRoaXMgY29tcGFyaXNvbi4gCmBgYHtyIGRzcF9jb21wX2Rvd25sb2FkfQppZighZXhpc3RzKCJkc3BfcHViY29tcCIpKXsKICAgICAgICBzZXR3ZCgifi9Eb2N1bWVudHMvUHJvamVjdHMvZHNwL2RhcmtzcGFjZXByb2plY3QvZHNwX2NvbXBhcmlzb24vcmVzdWx0cy8iKQogICAgICAgIGRzcF9wdWJjb21wTmFtZXMgPSBmcmVhZCgnY2F0IHB1YmNvbXBfdGFibGVfZmluYWwudHh0Lmd6IHwgZ3VuemlwIHwgaGVhZCAtbiAxJylbLCBjb2xuYW1lcyguU0QpXQogICAgICAgIGRzcF9wdWJjb21wID0gZnJlYWQoJ2NhdCBwdWJjb21wX3RhYmxlX2ZpbmFsLnR4dC5neiB8IGd1bnppcCB8IGdyZXAgLXYgIl5EYXkiJykKICAgICAgICBzZXRuYW1lcyhkc3BfcHViY29tcCwgZHNwX3B1YmNvbXBOYW1lcykKICAgICAgICBzZXR3ZCgifi9Eb2N1bWVudHMvUHJvamVjdHMvZHNwL0RhcmtTcGFjZS9tYW51YWxfZXZhbHVhdGlvbi9yb3VuZDIvIikKfQpgYGAKCiMjIyMjIEluY29ycG9yYXRpbmcgJiBmb3JtYXR0aW5nIGRhdGFzZXQgaW5mbyB0byByYW5rZWQgbGlzdHMKYGBge3IgcmFua2VkX29yaWdpbn0KZHNwX3Njb3JlZF9yZDMkcG1pZCA8LSBhcy5jaGFyYWN0ZXIoZHNwX3Njb3JlZF9yZDMkcG1pZCkKZHNwX3Njb3JlZF9yZDNfb3JpIDwtIHVuaXF1ZShtZXJnZShkc3Bfc2NvcmVkX3JkMyxkc3BfcHViY29tcCxieSA9ICJwbWlkIixhbGwueD1ULGFsbC55PUYpKQpkc3Bfc2NvcmVkX3JkM19vcmlfc2VsIDwtIGRzcF9zY29yZWRfcmQzX29yaVssLihwbWlkLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxldmFuY2UsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtub3duLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYl9zY29yZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGFya19zcGFjZV9pbnRlcmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGFya19zcGFjZV9wYXJ0aWFsX2ludGVyZXN0LAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbWV4ID0gZ3N1YigiMSIsIklNRXgiLGltZXgueSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlYWN0b21lID0gZ3N1YigiMSIsInJlYWN0b21lIixyZWFjdG9tZS55KSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG1fZXBtYyA9IGdzdWIoIjEiLCJ0bV9lcG1jIix0bV9lcG1jKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgRVZFWCA9IGdzdWIoIjEiLCJFVkVYIixFVkVYKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQmlvR1JJRCA9IGdzdWIoIjEiLCJCaW9HUklEIixCaW9HUklEKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgR09fSVBJID0gZ3N1YigiMSIsIkdPX0lQSSIsR09fSVBJKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT21uaVBhdGhfaW50ZXJhY3Rpb25zID0gZ3N1YigiMSIsIk9tbmlQYXRoX2ludGVyYWN0aW9ucyIsT21uaVBhdGhfaW50ZXJhY3Rpb25zKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgT21uaVBhdGhfcHRtID0gZ3N1YigiMSIsIk9tbmlQYXRoX3B0bSIsT21uaVBhdGhfcHRtKSldCgpmd3JpdGUoZHNwX3Njb3JlZF9yZDNfb3JpX3NlbCwiLi9kc3Bfc2NvcmVkX3JkM19vcmlfc2VsLnR4dCIsY29sLm5hbWVzID0gVCxyb3cubmFtZXMgPSBGLHNlcD0iXHQiLHF1b3RlID0gRikKCmRzcF9zY29yZWRfcmQzX29yaV9sb25nIDwtIHJlc2hhcGUoZHNwX3Njb3JlZF9yZDNfb3JpX3NlbCxkaXJlY3Rpb249ImxvbmciLHYubmFtZXM9Im9yaWdpbiIsdmFyeWluZz1jKCJpbWV4IiwicmVhY3RvbWUiLCJ0bV9lcG1jIiwiRVZFWCIsIkJpb0dSSUQiLCJHT19JUEkiLCJPbW5pUGF0aF9pbnRlcmFjdGlvbnMiLCJPbW5pUGF0aF9wdG0iKSkKZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfc2VsIDwtIHVuaXF1ZShkc3Bfc2NvcmVkX3JkM19vcmlfbG9uZ1tvcmRlcihwbWlkLC1vcmlnaW4pLC4ocG1pZCxyZWxldmFuY2Usa25vd24sZGJfc2NvcmUsZGFya19zcGFjZV9pbnRlcmVzdCxkYXJrX3NwYWNlX3BhcnRpYWxfaW50ZXJlc3Qsb3JpZ2luLGlkKV0pCgpkc3Bfc2NvcmVkX3JkM19vcmlfbG9uZ19zZWwkc2VsZWN0IDwtICJ5ZXMiCgpmb3IgKGkgaW4gMjpucm93KGRzcF9zY29yZWRfcmQzX29yaV9sb25nX3NlbCkpewogICAgICAgIGlmKGRzcF9zY29yZWRfcmQzX29yaV9sb25nX3NlbFtpLF0kcG1pZCA9PSBkc3Bfc2NvcmVkX3JkM19vcmlfbG9uZ19zZWxbaS0xLF0kcG1pZCAmIGRzcF9zY29yZWRfcmQzX29yaV9sb25nX3NlbFtpLF0kb3JpZ2luPT0iMCIpewogICAgICAgICAgICAgICAgZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfc2VsW2ksXSRzZWxlY3QgPC0gIm5vIgogICAgICAgIH0KICAgICAgICAKfQoKZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfZmluYWwgPC0gZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfc2VsW3NlbGVjdD09InllcyIsLihwbWlkLHJlbGV2YW5jZSxrbm93bixkYl9zY29yZSxkYXJrX3NwYWNlX2ludGVyZXN0LGRhcmtfc3BhY2VfcGFydGlhbF9pbnRlcmVzdCxvcmlnaW4saWQpXQoKdGFibGUoZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfZmluYWwka25vd24sZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfZmluYWwkb3JpZ2luLHVzZU5BID0gImlmYW55IikKYGBgClRoZSAKCiMjIyMjIFBsb3RzIG9yaWdpbiBjb21wYXJpc29uCmBgYHtyIHBsb3Rfb3JpZ2luMX0KZzMuOCA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfZmluYWwsYWVzKHg9cmVsZXZhbmNlLGZpbGw9a25vd24pKQpnMy44IDwtIGczLjggKyBnZW9tX2hpc3RvZ3JhbShhbHBoYT0wLjgscG9zaXRpb249J2lkZW50aXR5JykKZzMuOCA8LSBnMy44ICsgeGxhYigicmVsZXZhbmNlIHNjb3JlIikKZzMuOCA8LSBnMy44ICsgeWxhYigiTnVtYmVyIG9mIHB1YmxpY2F0aW9ucyIpCmczLjggPC0gZzMuOCArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSBkaXN0cmlidXRpb24sIHJvdW5kIDMiKQpnMy44IDwtIGczLjggKyBmYWNldF9ncmlkKG9yaWdpbn4uLHNjYWxlcz0iZnJlZV95IikKZzMuOCA8LSBnMy44ICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dCgpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpKQoKZzMuOApgYGAKCmBgYHtyIHBsb3Rfb3JpZ2luMn0KZzMuOSA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDNfb3JpX2xvbmdfZmluYWwsYWVzKHg9cmVsZXZhbmNlLGZpbGw9a25vd24pKQpnMy45IDwtIGczLjkgKyBnZW9tX2RlbnNpdHkoYWxwaGE9MC45LHBvc2l0aW9uPSdpZGVudGl0eScpCmczLjkgPC0gZzMuOSArIHhsYWIoInJlbGV2YW5jZSBzY29yZSIpCmczLjkgPC0gZzMuOSArIHlsYWIoIk51bWJlciBvZiBwdWJsaWNhdGlvbnMiKQpnMy45IDwtIGczLjkgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgZGlzdHJpYnV0aW9uLCByb3VuZCAzIikKZzMuOSA8LSBnMy45ICsgZmFjZXRfZ3JpZChvcmlnaW5+LixzY2FsZXM9ImZyZWVfeSIpCmczLjkgPC0gZzMuOSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKCmczLjkKYGBgCgojIyMjIENoZWNraW5nIGRzcCBpbnRlcmVzdCB2cyByZWxldmFuY2Ugc2NvcmUKCmBgYHtyIHBsb3RfY29tYl9vcmlfMX0KZzMuMTAgPC0gZ2dwbG90KGRzcF9zY29yZWRfcmQzX29yaV9sb25nX2ZpbmFsLGFlcyh4PXJlbGV2YW5jZSx5PWRhcmtfc3BhY2VfaW50ZXJlc3QsY29sb3VyPWtub3duKSkKZzMuMTAgPC0gZzMuMTAgKyBnZW9tX3BvaW50KGFscGhhPTAuNSkKZzMuMTAgPC0gZzMuMTAgKyB4bGFiKCJyZWxldmFuY2Ugc2NvcmUiKQpnMy4xMCA8LSBnMy4xMCArIHlsYWIoImRzcCBpbnRlcmVzdCAodHJ1bmNhdGVkIHRvcCBhdCAxMDApIikKZzMuMTAgPC0gZzMuMTAgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCwgcGVyIG9yaWdpbiIpCmczLjEwIDwtIGczLjEwICsgZmFjZXRfZ3JpZChvcmlnaW5+LixzY2FsZXM9ImZyZWVfeSIpCmczLjEwIDwtIGczLjEwICsgeWxpbSgwLjAsMTAwKQpnMy4xMCA8LSBnMy4xMCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKZzMuMTAKYGBgCgpgYGB7ciBwbG90X2NvbWJfb3JpXzJ9CmczLjExIDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkM19vcmlfbG9uZ19maW5hbCxhZXMoeD1yZWxldmFuY2UseT1kYXJrX3NwYWNlX2ludGVyZXN0LGNvbG91cj1rbm93bikpCmczLjExIDwtIGczLjExICsgZ2VvbV9zbW9vdGgoYWxwaGE9MC41KQpnMy4xMSA8LSBnMy4xMSArIHhsYWIoInJlbGV2YW5jZSBzY29yZSIpCmczLjExIDwtIGczLjExICsgeWxhYigiZHNwIGludGVyZXN0IikKZzMuMTEgPC0gZzMuMTEgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCwgc21vb3RoIHBsb3QiKQpnMy4xMSA8LSBnMy4xMSArIGZhY2V0X2dyaWQob3JpZ2lufi4sc2NhbGVzPSJmcmVlX3kiKQpnMy4xMSA8LSBnMy4xMSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSkKZzMuMTEKYGBgCgpgYGB7ciBwbG90X2NvbWJfb3JpXzN9CmczLjEyIDwtIGdncGxvdChkc3Bfc2NvcmVkX3JkM19vcmlfbG9uZ19maW5hbCxhZXMoeD1yZWxldmFuY2UseT1kYXJrX3NwYWNlX2ludGVyZXN0LGNvbG91cj1rbm93bikpCmczLjEyIDwtIGczLjEyICsgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIsZm9ybXVsYT15fngsYWxwaGE9MC41KQpnMy4xMiA8LSBnMy4xMiArIHhsYWIoInJlbGV2YW5jZSBzY29yZSIpCmczLjEyIDwtIGczLjEyICsgeWxhYigiZHNwIGludGVyZXN0IikKZzMuMTIgPC0gZzMuMTIgKyBnZ3RpdGxlKCJSZWxldmFuY2Ugc2NvcmUgdnMgRGFyayBTcGFjZSBpbnRlcmVzdCwgTE0gZml0dGVkIikKZzMuMTIgPC0gZzMuMTIgKyBmYWNldF9ncmlkKG9yaWdpbn4uLHNjYWxlcz0iZnJlZV95IikKZzMuMTIgPC0gZzMuMTIgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmczLjEyCmBgYAoKIyMjIENvbXBhcmlzb24gd2l0aCByb3VuZCAxCgpBZnRlciBtYW51YWwgZXZhbHVhdGlvbiwgaXQgc2VlbXMgdGhlIHJlbGV2YW5jZSBzY29yZSBoYXMgbG9zdCB0aGUgcG93ZXIgdG8gcHJlZGljdCB3aGV0aGVyIGEgcHVibGljYXRpb24gY29udGFpbnMgaW50ZXJhY3Rpb25zIG9yIG5vdC4gSSB3aWxsIGNvbXBhcmUgdG8gdGhlIGZpcnN0IHJvdW5kIG9mIHNjb3JpbmcgdG8gc2VlIHdoZXJlIGxpZSB0aGUgZGlmZmVyZW5jZXMuCgojIyMjIE1lcmdlIGRhdGFzZXRzCmBgYHtyIG1lcmdpbmdfcmQxJjN9CmRzcF9zY29yZWRfcmQxJHBtaWQgPC0gYXMuY2hhcmFjdGVyKGRzcF9zY29yZWRfcmQxJGAjSURgKQpkc3Bfc2NvcmVkX3JkMV9zZWwgPC0gZHNwX3Njb3JlZF9yZDFbLC4ocG1pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbF9yZDE9UmVsZXZhbmNlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgSU1FWCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvdmVyYWdlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvdGVpbnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm90X2ludGVyZXN0ID0gYFByb3RlaW4gaW50ZXJlc3RgLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tYl9zY29yZSA9IGBDb21iaW5lZCBzY29yZWApXQogICAgICAgIApkc3Bfc2NvcmVkX3JkMV9wbHVzXzMgPC0gZGF0YS50YWJsZSh1bmlxdWUobWVyZ2UoZHNwX3Njb3JlZF9yZDFfc2VsLGRzcF9zY29yZWRfcmQzX29yaV9zZWwsYnk9InBtaWQiLGFsbCA9IFQpKSkKCnRhYmxlKGRzcF9zY29yZWRfcmQxX3BsdXNfMyRrbm93bixkc3Bfc2NvcmVkX3JkMV9wbHVzXzMkSU1FWCx1c2VOQSA9ICJpZmFueSIpCmBgYApUaGVyZSBhcmUgMzg1IElNRXggZW50cmllcyB0aGF0IGFyZSBub3QgaW4gdGhlICdrbm93bicgc2V0LiBIb3cgaXMgdGhhdCBwb3NzaWJsZT8gTW9zdCBpbXBvcnRhbnRseSwgb3ZlciAyNSwwMDAga25vd24gcHVibGljYXRpb25zIGFyZSBub3QgcGFydCBvZiB0aGUgSU1FeCBkYXRhc2V0LiBUaGlzIHdpbGwgYmUgbW9zdGx5IEJpb0dSSUQgZGF0YS4gCgoKIyMjIyBQbG90IHJlbGV2YW5jZSByZDEgdnMgcmQzCgpGaXJzdCBJIHdpbGwgZXhwbG9yZSBob3cgdGhlIGRpZmZlcmVudCByZWxldmFuY2Ugc2NvcmVzIHJlbGF0ZSB0byBlYWNoIG90aGVyLgpgYGB7ciByZWxfc2NfY29tcH0KZzQgPC0gZ2dwbG90KGRzcF9zY29yZWRfcmQxX3BsdXNfMyxhZXMoeD1yZWxldmFuY2UseT1yZWxfcmQxLGNvbG91cj1rbm93bixncm91cD1JTUVYKSkKI2c0IDwtIGc0ICsgZ2VvbV9wb2ludChhbHBoYT0wLjUsYWVzKHNoYXBlPUlNRVgpKQpnNCA8LSBnNCArIGdlb21fcG9pbnQoYWxwaGE9MC41KQpnNCA8LSBnNCArIHhsYWIoInJlbGV2YW5jZSBzY29yZSByZDMiKQpnNCA8LSBnNCArIHlsYWIoInJlbGV2YW5jZSBzY29yZSByZDEiKQpnNCA8LSBnNCArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSByZDEgdnMgcmQzIikKZzQgPC0gZzQgKyBmYWNldF9ncmlkKElNRVh+LixzY2FsZXM9ImZyZWVfeSIpCiNnNCA8LSBnNCArIHlsaW0oMC4wLDEwMCkKZzQgPC0gZzQgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmc0CmBgYAoKTm93IEkgcmVwcmVzZW50IHRoZSBzYW1lIHBsb3QgYnkgc291cmNlIGRhdGEuIEkgbmVlZCB0byB3cmFuZ2xlIHRoZSBjb21wYXJpc29uIHRvICdsb25nJyBmb3JtYXQgZmlyc3QuIApgYGB7ciByZDEmM19sb25nfQpkc3Bfc2NvcmVkX3JkMV9wbHVzXzMgPC0gZHNwX3Njb3JlZF9yZDFfcGx1c18zWyxpbl9JTUV4Oj1pZmVsc2UoSU1FWD09InRydWUiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJJTUV4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiMCIpXQpkc3Bfc2NvcmVkX3JkMV9wbHVzXzNfbG9uZyA8LSByZXNoYXBlKGRzcF9zY29yZWRfcmQxX3BsdXNfMyxkaXJlY3Rpb249ImxvbmciLHYubmFtZXM9Im9yaWdpbiIsdmFyeWluZz1jKCJpbl9JTUV4IiwicmVhY3RvbWUiLCJ0bV9lcG1jIiwiRVZFWCIsIkJpb0dSSUQiLCJHT19JUEkiLCJPbW5pUGF0aF9pbnRlcmFjdGlvbnMiLCJPbW5pUGF0aF9wdG0iKSkKZHNwX3Njb3JlZF9yZDFfcGx1c18zX2xvbmdfc2VsIDwtIHVuaXF1ZShkc3Bfc2NvcmVkX3JkMV9wbHVzXzNfbG9uZ1tvcmRlcihwbWlkLC1vcmlnaW4pLC4ocG1pZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWxfcmQxLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlbGV2YW5jZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBrbm93biwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW4sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGJfc2NvcmUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGFya19zcGFjZV9pbnRlcmVzdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXJrX3NwYWNlX3BhcnRpYWxfaW50ZXJlc3QpXSkKCmRzcF9zY29yZWRfcmQxX3BsdXNfM19sb25nX3NlbCRzZWxlY3QgPC0gInllcyIKCmZvciAoaSBpbiAyOm5yb3coZHNwX3Njb3JlZF9yZDFfcGx1c18zX2xvbmdfc2VsKSl7CiAgICAgICAgaWYoZHNwX3Njb3JlZF9yZDFfcGx1c18zX2xvbmdfc2VsW2ksXSRwbWlkID09IGRzcF9zY29yZWRfcmQxX3BsdXNfM19sb25nX3NlbFtpLTEsXSRwbWlkICYgZHNwX3Njb3JlZF9yZDFfcGx1c18zX2xvbmdfc2VsW2ksXSRvcmlnaW49PSIwIil7CiAgICAgICAgICAgICAgICBkc3Bfc2NvcmVkX3JkMV9wbHVzXzNfbG9uZ19zZWxbaSxdJHNlbGVjdCA8LSAibm8iCiAgICAgICAgfQogICAgICAgIAp9Cgpkc3Bfc2NvcmVkX3JkMV9wbHVzXzNfbG9uZ19maW5hbCA8LSBkc3Bfc2NvcmVkX3JkMV9wbHVzXzNfbG9uZ19zZWxbc2VsZWN0PT0ieWVzIiwuKHBtaWQscmVsX3JkMSxyZWxldmFuY2Usa25vd24sZGJfc2NvcmUsZGFya19zcGFjZV9pbnRlcmVzdCxkYXJrX3NwYWNlX3BhcnRpYWxfaW50ZXJlc3Qsb3JpZ2luKV0KCnRhYmxlKGRzcF9zY29yZWRfcmQxX3BsdXNfM19sb25nX2ZpbmFsJGtub3duLGRzcF9zY29yZWRfcmQxX3BsdXNfM19sb25nX2ZpbmFsJG9yaWdpbix1c2VOQT0iaWZhbnkiKQpgYGAKCgoKYGBge3IgcmVsX3NjX2NvbXBfb3JpZ2lufQpnNSA8LSBnZ3Bsb3QoZHNwX3Njb3JlZF9yZDFfcGx1c18zX2xvbmdfZmluYWwsYWVzKHg9cmVsZXZhbmNlLHk9cmVsX3JkMSxjb2xvdXI9b3JpZ2luLGdyb3VwPWtub3duKSkKI2c1IDwtIGc1ICsgZ2VvbV9wb2ludChhbHBoYT0wLjUsYWVzKHNoYXBlPUlNRVgpKQpnNSA8LSBnNSArIGdlb21fcG9pbnQoYWxwaGE9MC4yKQpnNSA8LSBnNSArIHhsYWIoInJlbGV2YW5jZSBzY29yZSByZDMiKQpnNSA8LSBnNSArIHlsYWIoInJlbGV2YW5jZSBzY29yZSByZDEiKQpnNSA8LSBnNSArIGdndGl0bGUoIlJlbGV2YW5jZSBzY29yZSByZDEgdnMgcmQzIikKZzUgPC0gZzUgKyBmYWNldF9ncmlkKGtub3dufi4pCiNnNSA8LSBnNSArIHlsaW0oMC4wLDEwMCkKZzUgPC0gZzUgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCmc1CmBgYA==